Данный отчет является частью исследования бренда отеля Wawelberg. В качестве данных были использованы отзывы на 7 отелей с Booking.com и Yandex путешествия. В качестве отелей-конкурентов были взяты: Astoria, Four Seasons, Lotte, Grand Europe, Grand Hotel Moika 22 и SO.

В этом документе представлены следующие графики:

  1. График распределения количества отзывов по месяцам;

  2. График распределения отзывов в % (Сколько отзывов было написано на каждый отель);

  3. Диаграмма распределения оценок отзывов по месяцам;

  4. Диаграмма распределения отзывов по сентименту (негативные/позитивные) для каждого отеля;

  5. Сводная таблица с информацией о длине отзывов для каждого отеля (мин-макс, среднее, медиана);

  6. График с частыми существительными, прилагательными и глаголами для каждого отеля (топ-10);

  7. График с наиболее характерными существительными, прилагательными и глаголами, с которыми ассоциируется отель (топ-10).

Общая статистика по отзывам

Сводная таблица по отзывам

В данной таблице представлена информация о количестве отзывов, собранных с Booking и Яндекс Путешествий. К сожалению, отель Grand Hotel Moika 22 не был представлен на Booking.com, поэтому данные по нему были собраны только с Яндекс Путешествий.

data_all_summary = data_all %>% group_by(Hotel) %>% dplyr::summarise(number_of_reviews = n(), stars_mean = round(mean(stars)), stars_median = median(stars), stars_min = min(stars), stars_max = max(stars), min_date = min(date), max_date = max(date)) 

data_all_summary = cbind(data_all_summary, data_all %>% filter(!is.na(review_text)) %>%  group_by(Hotel) %>% summarise(NAs = n(), length_mean = round(mean(length),0)) %>% select(-Hotel)) %>% select(Hotel, number_of_reviews, NAs, stars_mean, stars_median, stars_min, stars_max, min_date, max_date, length_mean) 

data_all_summary$number_of_reviews = as.numeric(data_all_summary$number_of_reviews)
data_all_summary$NAs = as.numeric(data_all_summary$NAs)

data_all_summary = data_all_summary %>%
                           group_by(Hotel) %>%
                           mutate(differ = paste0(round(NAs/number_of_reviews,2)*100, "%")) %>% select(Hotel, number_of_reviews, differ, stars_mean, stars_median, stars_min, stars_max, min_date, max_date, length_mean) 
 
data_all_summary %>%
  datatable(colnames = c('Отель' = 2, 'Кол-во отзывов' = 3, '%  Отзывов с текстом' = 4,'Ср. оценка отзывов' = 5, 'Медиана оценки отзывов' = 6, 'Мин. оценка' = 7, 'Макс. оценка' = 8, 'Дата первого отзыва' = 9, 'Дата последнего отзыва' = 10, 'Cр. длина отзывов' = 11), options = list(pageLength=7))

Больше всего отзывов было у Grand Europe, Astoria и Lotte. При этом у Вавельберг было больше всего отзывов с текстом, а также средняя длина отзывов выше, чем у остальных отелей, что говорит о наличии более качественных отзывов на отель Вавельберг. В целом мы видим, что на отель Вавельберг первые отзывы датируются годом открытия, поэтому стоит также рассмотреть статистику, начиная с апреля 2021 года.

data_all_summary = data_all %>% filter(date >= "2021-04-01") %>% group_by(Hotel) %>% dplyr::summarise(number_of_reviews = n(), stars_mean = round(mean(stars)), stars_median = median(stars), stars_min = min(stars), stars_max = max(stars), min_date = min(date), max_date = max(date)) 

data_all_summary = cbind(data_all_summary, data_all %>% filter(date >= "2021-04-01") %>% filter(!is.na(review_text)) %>%  group_by(Hotel) %>% summarise(NAs = n(), length_mean = round(mean(length),0)) %>% select(-Hotel)) %>% select(Hotel, number_of_reviews, NAs, stars_mean, stars_median, stars_min, stars_max, min_date, max_date, length_mean) 

data_all_summary$number_of_reviews = as.numeric(data_all_summary$number_of_reviews)
data_all_summary$NAs = as.numeric(data_all_summary$NAs)

data_all_summary = data_all_summary %>%
                           group_by(Hotel) %>%
                           mutate(differ = paste0(round(NAs/number_of_reviews,2)*100, "%")) %>% select(Hotel, number_of_reviews, differ, stars_mean, stars_median, stars_min, stars_max, min_date, max_date, length_mean) 
 
data_all_summary %>%
  datatable(colnames = c('Отель' = 2, 'Кол-во отзывов' = 3, '%  Отзывов с текстом' = 4,'Ср. оценка отзывов' = 5, 'Медиана оценки отзывов' = 6, 'Мин. оценка' = 7, 'Макс. оценка' = 8, 'Дата первого отзыва' = 9, 'Дата последнего отзыва' = 10, 'Cр. длина отзывов' = 11), options = list(pageLength=7))

Разрыв между отзывами на Wawelberg и другие отели сократился, но по количеству отзывов ему удалось опередить только SO. При этом по качеству отзывов отзывы на Wawelberg продолжаю занимать лидирующие позиции.

### Таблица с наиболее длинными отзывами по каждому отелю

# data_all = data_all %>% filter(!is.na(length)) 
# 
# data_all %>% group_by(Hotel) %>% slice_max(order_by = length, n = 5) %>% select(Hotel, review_text, date, stars) %>%
#   datatable(colnames = c('Отель' = 2, 'Отзыв' = 3, 'Дата' = 4, 'Кол-во звезд' = 4), filter = 'top', options = list(pageLength=10, scrollX='400px', scrollY='350px'))

Сезонность отзывов

Далее перед нами стоял вопрос распределения числа отзывов в конкретные месяца и года среди разных отелей. Этот график поможет понять, был ли отель популярнее других в опредеденный промежуток времени или, наоборот, менее интересен для гостей нашего города.

По графику мы видим, что каких-то внесезонных или сезонных аномалий характернвх для Wawelberg не наблюдалось. Отзывы с одинаковой сезонностью были написаны в августе 2021 года, январе 2022, мае 2022, августе 2022.

Диаграмма отзывов в процентах

С помощью диаграммы, отражающей процентное соотношение отзывов на каждый отель от общего числа отзывов удобно смотреть на долю отеля на рынке и его популярность среди гостей города. Из-за того, что отзывы на Wawelberg появляются с апреля 2021 года, стоит использовать предложенный фильтр по годам.

# display.brewer.pal(n = 8, name = 'Set1')
# brewer.pal(n = 8, name = "Set1")
# 
pal = c("#377EB8", "#FF7F00", "#4DAF4A", "#E41A1C", "#984EA3", "#A65628", "#F781BF")
names(pal) = c("Grand europe" , "Astoria", "Lotte", "Four seasons", "Moika 22", "SO", "Wawelberg")
# 
# updated_pal = pal[unique(as.character(data_all$Hotel))]

date_month$year = year(date_month$date)

shared_date <- SharedData$new(date_month %>% select(-date))

# colors <- c('rgb(211,94,96)', 'rgb(128,133,133)', 'rgb(144,103,167)', 'rgb(171,104,87)', 'rgb(114,147,203)', 'blue')

bscols(widths = c(2, 10),
       list(
       filter_checkbox("year", "Год", shared_date, ~year),
       filter_checkbox("Hotel", "Отель", shared_date, ~Hotel)),
  
  plot_ly(shared_date, labels = ~factor(Hotel), values = ~count,
          opacity = 0.8,
          textfont = list(color = "white", size = 10),
        textposition = 'inside',
        textinfo = 'label+percent', showlegend = F
        )  %>%
  add_pie(hole = 0,) %>%
    layout(
         xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
         yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
)
# display.brewer.pal(n = 12, name = 'Paired')
# 
# brewer.pal(n = 12, name = 'Paired')
# date_month2022 = date_month %>% filter(("2021-10-01" <= date) & (date <= "2022-10-01"))
# 
# shared_date2022 <- SharedData$new(date_month2022 %>% select(-date))
# 
#   plot_ly(shared_date2022, labels = ~Hotel, values = ~count,
#           colors = pal,
#           opacity = 0.8,
#           textfont = list(color = "white", size = 10),
#           type = 'pie',
#         textposition = 'inside',
#         textinfo = 'label+percent', showlegend = F,
#         marker = list(line = list(color = '#FFFFFF'))) %>%
#     layout(title = "Процентное соотношение отзывов по месяцам для отелей\n (с окт. 2021 по окт. 2022)", font=list(size = 10),
#          xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
#          yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE), margin = margin)
# date_month21 = date_month %>% filter(("2020-10-01" <= date) & (date <= "2021-10-01"))
# shared_date2021 <- SharedData$new(date_month21%>% select(-date))
# 
# plot_ly(shared_date2021, 
#         labels = ~Hotel, 
#         values = ~count,
#         colors = pal,
#         opacity = 0.80,
#         textfont = list(color = "white", size = 10),
#         textposition = 'inside', 
#         textinfo = 'label+percent', 
#         showlegend = F) %>%
#   add_pie(hole = 0) %>%
#     layout(title = "Процентное соотношение отзывов по месяцам для отелей\n (с окт. 2020 по окт. 2021)",
#          xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = TRUE),
#          yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = TRUE),
#            font=list(size = 10),
#          margin = margin)

Диаграмма распределения оценок отзывов по месяцам

Оценки на отель ставяься вместе с отзывами. Оценки на Яндекс.Путешествия были представлены в виде шкале от 0 до 5, а на Booking от 1 до 10. Оценки были приведены к единому формату и в итоговом варианте варьировались от 1 до 5.

График, представленный ниже иллюстрирует средние оценки для отелей по месяцам. Начиная с момента открытия отеля Wawelberg, его оценка не показывала сильных падений, а также за весь период существования отеля показывает наилучший результат. Тем не менне, в июле, сентябре и августе наблюдалось значительное падение средней оценки.

########## Отдельная визуализация для 2021 по 2022 г
# plot_ly(date_score %>% filter(("2021-10-01" <= date) & (date <= "2022-10-01")),
#         x = ~date,
#         y = ~mean,
#         split=~Hotel,
#         color=~Hotel, 
#         # colors = c("red", "blue", "chartreuse3"), 
#         colors = "Dark2" , 
#         type = 'scatter',
#         mode="lines",
#         width = 700, height = 400) %>% 
#   layout(title = "Средние оценки по месяцам для отелей\n (с окт.2021 по окт.2022)", font=list(size = 10), 
#          xaxis = list(title = "",
#               titlefont = list(size = 10),
#              showline = TRUE,
#              showgrid = FALSE,
#              showticklabels = TRUE,
#              tickfont = list(family = 'Roboto',
#                              size = 10,
#                              color = 'rgb(82, 82, 82)'), dtick = "M1", tickformat="%b<br>%Y"), 
#          yaxis = yaxis,
#          margin = margin)
######### Отдельная визуализация для 2020-2021 г.
# plot_ly(date_score %>% filter(("2020-10-01" <= date) & (date <= "2021-10-01")),
#         x = ~date,
#         y = ~mean,
#         split=~Hotel,
#         color=~Hotel, 
#         # colors = c("red", "blue", "chartreuse3"), 
#         colors = "Dark2" , 
#         type = 'scatter',
#         mode="lines",
#         width = 700, height = 400) %>% 
#   layout(title = "Средние оценки по месяцам для отелей\n (с окт.2020 по окт.2021)", font=list(size = 10), 
#          xaxis = list(title = "",
#               titlefont = list(size = 10),
#              showline = TRUE,
#              showgrid = FALSE,
#              showticklabels = TRUE,
#              tickfont = list(family = 'Roboto',
#                              size = 10,
#                              color = 'rgb(82, 82, 82)'), dtick = "M1", tickformat="%b<br>%Y"), 
#          yaxis = yaxis,
#          margin = margin)

Сводная таблица с информацией о длине отзывов для каждого отеля (мин-макс, среднее, медиана)

Characteristic Astoria, N = 1,928 Four seasons, N = 1,364 Grand europe, N = 2,780 Lotte, N = 1,561 Moika 22, N = 597 SO, N = 977 Wawelberg, N = 630
Длина отзыва
    Среднее 26 26 28 23 24 34 36
    Медиана 13 12 16 13 11 17 20
    Мин-Макс 1- 637 1- 451 1- 410 1- 336 1- 467 1- 635 1- 424
    Unknown 783 538 1,253 583 0 397 202

Процентное соотношение позитивных и негативных отзывов по отелям

Было предложено посмотреть на распределение негативных/позитивных отзывов по месяцам. Для определения эмоциональной окраски, использовался словарь “Карта слов”. Для каждого отзыва была вычислена эмоциональная оценка, где позитивным считался отзыв со значением более или равно 0.45, нейтральный отзыв от 0.45 до -0.1 и негативным считались все отзывы. набравшие оценку менее -0.1.

На графике мы можем видеть неравномерное распределение позитивных, нейтральных и негативных отзывов. Преобладание позитивных отзывов над негативными - частое яявление для отзывов. Тем не меннее, наибольшее число позитивных отзывов было определено в SO и Wawelberg.

Также мы можем посмотреть на более детальное распределение оценок на отзывы для каждого отеля. В основном, это оценки 5 и 4. Тем не менее из данных видно, что оценку “3” чаще других получают отели SO и Moika22, в то время как у отеля Wawelberg впринципе нет оценок 2 и 3.

Частые слова для каждого отеля (топ-10)

В этом блоке представлены слова, которые наиболее характерны для каждого отеля. При этом слова разбиты на существительные, прилагательные и глаголы. Метрикой для определения наиболее характерных слов была выбрана частота упоминания слова в отзывах.

Наиболее характерные слова для каждого отеля

Частота упоминания слова в отзывах может не показывать слова, которые уникальны для конкретного отеля.

Поэтому был использован дополнительный метод оценки уникальности слова для отелей.

Используемый метод: tf-id. Идея tf-idf состоит в том, чтобы найти важные слова для содержания каждого документа, уменьшив вес для часто используемых слов и увеличив вес для слов, которые не очень часто используются в коллекции или корпусе документов.